/*
 ******************************
 * Object Oriented Programming in C
 *
 * Author: Laurent Deniau, Laurent.Deniau@cern.ch
 *
 * For more information, please see the paper:
 * http://home.cern.ch/ldeniau/html/oopc/oopc.html
 *
 ******************************
 */

#include <stdio.h>
#include <time.h>
#include <math.h>
#include <array.h>

#define ARRSIZE 1000
#define NUMLOOP 100000
#define NUMTEST 10

#define SQR(a) ((a)*(a))
#define STAT(n,sx,sx2) do { \
        if ((n)>1) { \
          (sx) /= (n); \
          (sx2) = ((sx2) - (n)*SQR(sx))/((n)-1); \
        } else (sx2) = 0; } while(0)


static void
set(double *d, size_t i, double v)
{
  d[i] = v;
}

int
main(void)
{
  int i, n, t;
  time_t t0, t1;
  double *data, dt[3] = {0}, dt2[3] = {0};
  void (*pf_set)(double *d, size_t i, double v) = set;

  t_darray *const darr = darray.new(ARRSIZE);
  t_iarray *const iarr = iarray.new(ARRSIZE);

  printf("%d allocated dmemBlock(s) in memory\n", dmemBlock.numBlock());
  printf("%d allocated imemBlock(s) in memory\n", imemBlock.numBlock());
  data = sendMsg(darr, getData);

  printf("running %d tests (%d loops) ", NUMTEST, NUMTEST*NUMLOOP);

  for(t=0; t<NUMTEST; t++) {

    putchar('.'); fflush(stdout);

    t0 = time(NULL);
    for(n=0; n<NUMLOOP; n++)
      for(i=0; i<ARRSIZE; i++) data[i] = i;
    t1 = time(NULL);
    dt [0] += t1-t0;
    dt2[0] += SQR(t1-t0);

    t0 = time(NULL);
    for(n=0; n<NUMLOOP; n++)
      for(i=0; i<ARRSIZE; i++) pf_set(data,i,i);
    t1 = time(NULL);
    dt [1] += t1-t0;
    dt2[1] += SQR(t1-t0);

    t0 = time(NULL);
    for(n=0; n<NUMLOOP; n++)
      for(i=0; i<ARRSIZE; i++) sendMsg_(darr, set) i, i __;
    t1 = time(NULL);
    dt [2] += t1-t0;
    dt2[2] += SQR(t1-t0);
  }

  STAT(NUMTEST,dt[0],dt2[0]);
  STAT(NUMTEST,dt[1],dt2[1]);
  STAT(NUMTEST,dt[2],dt2[2]);

  putchar('\n');
  printf("time[data] = %g +/-%g [100%%]\n",
	 dt[0], sqrt(dt2[0]));
  printf("time[set]  = %g +/-%g [%.0f%%]\n",
	 dt[1], sqrt(dt2[1]), dt[1]/dt[0]*100);
  printf("time[send] = %g +/-%g [%.0f%%]\n",
	 dt[2], sqrt(dt2[2]), dt[2]/dt[0]*100);

  delete(darr);
  printf("%d allocated dmemBlock(s) in memory\n", dmemBlock.numBlock());
  printf("%d allocated imemBlock(s) in memory\n", imemBlock.numBlock());
  delete(iarr);
  printf("%d allocated imemBlock(s) in memory\n", imemBlock.numBlock());

  fputs("C++ (without inlining) should be ", stdout);
  if (dt[2]<dt[1]) {
    printf("%.1f%% +/-%g%% slower than OOPC\n",
	   (dt[1]-dt[2])/dt[2]*100, sqrt(dt2[1]+dt2[2])/dt[2]*100);
  } else {
    printf("%.1f%% +/-%g%% faster than OOPC\n",
	   (dt[2]-dt[1])/dt[1]*100, sqrt(dt2[1]+dt2[2])/dt[1]*100);
  }

  DEBUG_DISPMEM(stderr);

  return EXIT_SUCCESS;
}
